/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.message.config;

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigChangeListener;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;
import java.util.Set;

@Configuration
public class RedisConfig {

    private static final Logger logger = LoggerFactory.getLogger(RedisConfig.class);

    /**
     * redis连接
     * @return
     */
    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        logger.debug("begin init rbac connection factory!");
        Config config = ConfigService.getConfig("redis");
        JedisConnectionFactory cf = createConnectionFactory(config);
        config.addChangeListener(new RedisConfigListener(cf));
        return cf;
    }

    @Bean("stringRedisTemplate")
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory){
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
        stringRedisTemplate.setConnectionFactory(redisConnectionFactory);
        return stringRedisTemplate;
    }

    /**
     * 实际使用的redisTemplate，可以直接注入到代码中，直接操作redis
     */
    @Bean("redisTemplate")
    public RedisTemplate<String, Object> redisTemplate() {
        logger.debug("begin init redis template!");
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        //开启事务
        redisTemplate.setEnableTransactionSupport(true);
        RedisSerializer stringSerializer = new StringRedisSerializer();
        JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();

        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(jdkSerializationRedisSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(jdkSerializationRedisSerializer);
        redisTemplate.setDefaultSerializer(stringSerializer);
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        return redisTemplate;
    }

    protected static JedisConnectionFactory createConnectionFactory(Config config){
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxIdle(config.getIntProperty("redis.maxIdle",300));
        poolConfig.setMaxTotal(config.getIntProperty("redis.maxTotal",1000));
        poolConfig.setTestOnBorrow(config.getBooleanProperty("redis.testOnBorrow",true));
        poolConfig.setMaxWaitMillis(config.getIntProperty("redis.maxWaitMillis",-1));
        poolConfig.setTestWhileIdle(true);
        poolConfig.setNumTestsPerEvictionRun(10);
        poolConfig.setTimeBetweenEvictionRunsMillis(1000*4);

        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(poolConfig);
        jedisConnectionFactory.getStandaloneConfiguration().setHostName(config.getProperty("redis.host",""));
        jedisConnectionFactory.getStandaloneConfiguration().setPort(config.getIntProperty("redis.port",6379));
        jedisConnectionFactory.getStandaloneConfiguration().setPassword(config.getProperty("redis.pass",""));
        jedisConnectionFactory.getStandaloneConfiguration().setDatabase(config.getIntProperty("redis.dbindex",0));
        return jedisConnectionFactory;
    }

    protected static class RedisConfigListener implements ConfigChangeListener {

        private JedisConnectionFactory connectionFactory;

        public RedisConfigListener(JedisConnectionFactory connectionFactory) {
            this.connectionFactory = connectionFactory;
        }

        @Override
        public void onChange(ConfigChangeEvent changeEvent) {
            Set<String> changeKeys = changeEvent.changedKeys();
            if(changeKeys == null || changeKeys.isEmpty()){
                return;
            }
            Config config = ConfigService.getConfig(changeEvent.getNamespace());
            this.connectionFactory = createConnectionFactory(config);
        }

    }

}
